home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 24 / develop Issue 24 code / Scriptable Database 1.0a15 / Foundation / AbstractCollector.cp next >
Encoding:
Text File  |  1996-02-19  |  12.0 KB  |  388 lines  |  [TEXT/CWIE]

  1.  
  2. #include "AbstractCollector.h"
  3. #include "MarkToken.h"
  4.  
  5. //
  6. // We will sometimes be asked to retrieve "any" item,
  7. // in which case we will need to generate random numbers.
  8. //
  9. #include "PseudoRandom.h"
  10.  
  11. #include <AppleEvents.h>
  12. #include <AERegistry.h>
  13. #include <ASRegistry.h>
  14.  
  15. //========================================================================================
  16. //    Classs TCollectorBehavior
  17. //========================================================================================
  18.  
  19. ImplementSmallClassData(TCollectorBehavior, clCollectorBehavior);
  20.  
  21. //----------------------------------------------------------------------------------------
  22. // TCollectorBehavior::CollectorBehaviorOwner
  23. //----------------------------------------------------------------------------------------
  24. TAbstractCollector* TCollectorBehavior::CollectorBehaviorOwner() const
  25.     {
  26.     return (TAbstractCollector*)this->BehaviorOwner();
  27.     } // TCollectorBehavior::CollectorBehaviorOwner
  28.  
  29. //----------------------------------------------------------------------------------------
  30. // TCollectorBehavior::CollectorRequestDynamicBehavior
  31. //----------------------------------------------------------------------------------------
  32. long TCollectorBehavior::CollectorRequestDynamicBehavior(const TAETransaction& t, long requestID, void* param)
  33.     {
  34.     TCollectorBehavior* nextBehavior = this->NextCollectorBehavior();
  35.     
  36.     if(nextBehavior != nil)
  37.         return nextBehavior->CollectorRequestDynamicBehavior(t, requestID, param);
  38.     else
  39.         return this->CollectorBehaviorOwner()->CollectorRequestDefaultBehavior(t, requestID, param);
  40.     }
  41.  
  42. //========================================================================================
  43. //    Classs TAbstractCollector
  44. //========================================================================================
  45.  
  46. //----------------------------------------------------------------------------------------
  47. // TAbstractCollector::CollectorRequest
  48. //----------------------------------------------------------------------------------------
  49. long TAbstractCollector::CollectorRequest(const TAETransaction& t, long requestID, void* param /* = nil*/)
  50.     {
  51.     TCollectorBehavior* behavior = FirstCollectorBehavior();
  52.     
  53.     if(behavior != nil)
  54.         return behavior->CollectorRequestDynamicBehavior(t, requestID, param);
  55.     else
  56.         return this->CollectorRequestDefaultBehavior(t, requestID, param);
  57.     }
  58.     
  59. //----------------------------------------------------------------------------------------
  60. // TAbstractCollector::CollectorRequestDefaultBehavior
  61. //----------------------------------------------------------------------------------------
  62. long TAbstractCollector::CollectorRequestDefaultBehavior(const TAETransaction&, long requestID, void* /*param = nil*/)
  63.     {
  64.     long result = 0;
  65.     
  66.     switch(requestID)
  67.         {
  68.         case kWaitForAsyncSearchesToComplete:
  69.         case kAsyncSearchesComplete:
  70.             result = true;
  71.             break;
  72.  
  73.         case kSearchShouldIterateBackwards:
  74.         case kCollectionIsFull:
  75.             result = false;
  76.             break;
  77.                 
  78.         default:
  79.             result = kUnknownCollectorRequest;
  80.         }
  81.     
  82.     return result;
  83.     } // TAbstractCollector::CollectorRequestDefaultBehavior
  84.  
  85. //----------------------------------------------------------------------------------------
  86. // TAbstractCollector::~TAbstractCollector
  87. //----------------------------------------------------------------------------------------
  88. TAbstractCollector::~TAbstractCollector()
  89.     {
  90.     } // TAbstractCollector::~TAbstractCollector
  91.  
  92. //----------------------------------------------------------------------------------------
  93. // TAbstractCollector::FirstBehavior
  94. //----------------------------------------------------------------------------------------
  95. TBehavior* TAbstractCollector::FirstBehavior() const
  96.     {
  97.     return fFirstBehavior;
  98.     }
  99.     
  100. //----------------------------------------------------------------------------------------
  101. // TAbstractCollector::SetFirstBehavior
  102. //----------------------------------------------------------------------------------------
  103. void TAbstractCollector::SetFirstBehavior(TBehavior* firstBehavior)
  104.     {
  105.     fFirstBehavior = firstBehavior;
  106.     }
  107.  
  108. enum
  109.     {
  110.     kTakeFirstItemOnly = 'one!'                    // Used internally by TObjectCollector
  111.     };
  112.     
  113. //========================================================================================
  114. //    Classs TObjectCollector
  115. //========================================================================================
  116.  
  117. TObjectCollector::TObjectCollector(TDescriptor scopeOfSearch) :
  118.     fCollection(nil),
  119.     fScopeOfSearch(scopeOfSearch),
  120.     fCollectionFull(false),
  121.     fIterateBackwards(false),
  122.     fStartOfRange(1),
  123.     fEndOfRange(0x7FFFFFFF),
  124.     fPostProcessListStart(0),
  125.     fPostProcessListStop(0),
  126.     fNumberOfItemsAdded(0)
  127.     {
  128.     TDescriptor scopeOfSearchRecord;
  129.     
  130.     //
  131.     // First, process the single-descriptor entries.
  132.     // "every" item may be specified; any other possible
  133.     // value (any, middle, etc.) specifies but a single
  134.     // object.
  135.     //
  136.     if((scopeOfSearch.DescriptorType() == typeLongInteger) || (scopeOfSearch.DescriptorType() == typeAbsoluteOrdinal))
  137.         {
  138.         InterpretWhoseRangeEntry(scopeOfSearch, fStartOfRange, fEndOfRange, fPostProcessListStart);
  139.         //
  140.         // If the special processing mode is "any" or "middle" or
  141.         // something like that, then we only want to take a single
  142.         // item.
  143.         //
  144.         if(fPostProcessListStart != 0)
  145.             fPostProcessListStop = kTakeFirstItemOnly;
  146.         }
  147.     //
  148.     // Next, process range descriptors.  These are usually in the
  149.     // form "item X through item Y", but they may be much stranger
  150.     // than that ("middle item through any item", for example).
  151.     //
  152.     // n.b. The object support library always converts the formRange
  153.     // descriptor into a typeWhoseRange descriptor to make life easier
  154.     // for its clients.  We don't bother to do this conversion because
  155.     // we might as well just recognize formRange here, and not bother
  156.     // parsing it earlier.
  157.     //
  158.     // The following 'typeWhoseRange' code is only executed if
  159.     // AEResolve is used.
  160.     //
  161.     else if(scopeOfSearch.DescriptorType() == typeWhoseRange)
  162.         {
  163.         scopeOfSearchRecord = scopeOfSearch.Coerce(typeAERecord);
  164.         
  165.         TDescriptor temp;
  166.         long rangeTemp = 0;
  167.         
  168.         //
  169.         // Get the start and the end of the range
  170.         //
  171.         temp = scopeOfSearchRecord.GetDescriptorParameter(keyAEWhoseRangeStart);
  172.         InterpretWhoseRangeEntry(temp, fStartOfRange, rangeTemp, fPostProcessListStart);
  173.         temp.Dispose();
  174.         temp = scopeOfSearchRecord.GetDescriptorParameter(keyAEWhoseRangeStop);
  175.         InterpretWhoseRangeEntry(temp, rangeTemp, fEndOfRange, fPostProcessListStop);
  176.         temp.Dispose();
  177.         
  178.         //
  179.         // If the end of the range is the last item, that's nothing special.
  180.         //
  181.         if(fEndOfRange == -1)
  182.             {
  183.             fPostProcessListStop = 0;
  184.             fEndOfRange = 0x7FFFFFFF;
  185.             }
  186.         }
  187.     //
  188.     // The following 'formRange' code is only used if AEResolve is NOT used.
  189.     //
  190.     else if(scopeOfSearch.DescriptorType() == formRange)
  191.         {
  192.         scopeOfSearchRecord = scopeOfSearch.Coerce(typeAERecord);
  193.         
  194.         TDescriptor temp;
  195.         TDescriptor temp2;
  196.         DescType unusedDesiredClass;
  197.         DescType unusedKeyForm;
  198.         long rangeTemp = 0;
  199.         
  200.         //
  201.         // Get the start and the end of the range
  202.         //
  203.         temp2 = scopeOfSearchRecord.GetDescriptorParameter(keyAERangeStart);
  204.         temp2.GetObjectSpecifierParameters(unusedDesiredClass, unusedKeyForm, &temp);
  205.         InterpretWhoseRangeEntry(temp, fStartOfRange, rangeTemp, fPostProcessListStart);
  206.         temp.Dispose();
  207.         temp2.Dispose();
  208.         temp2 = scopeOfSearchRecord.GetDescriptorParameter(keyAERangeStop);
  209.         temp2.GetObjectSpecifierParameters(unusedDesiredClass, unusedKeyForm, &temp);
  210.         InterpretWhoseRangeEntry(temp, rangeTemp, fEndOfRange, fPostProcessListStop);
  211.         temp.Dispose();
  212.         temp2.Dispose();
  213.         
  214.         //
  215.         // If the end of the range is the last item, that's nothing special.
  216.         //
  217.         if(fEndOfRange == -1)
  218.             {
  219.             fPostProcessListStop = 0;
  220.             fEndOfRange = 0x7FFFFFFF;
  221.             }
  222.         }
  223.     
  224.     scopeOfSearchRecord.Dispose();
  225.     }
  226.  
  227. //----------------------------------------------------------------------------------------
  228. // TObjectCollector::CollectorRequestDefaultBehavior
  229. //----------------------------------------------------------------------------------------
  230. long TObjectCollector::CollectorRequestDefaultBehavior(const TAETransaction& t, long requestID, void* param /* = nil*/)
  231.     {
  232.     long result = 0;
  233.     
  234.     switch(requestID)
  235.         {
  236.         case kSearchShouldIterateBackwards:
  237.             result = fIterateBackwards;
  238.             break;
  239.             
  240.         case kCollectionIsFull:
  241.             result = fCollectionFull;
  242.             break;
  243.                 
  244.         default:
  245.             result = TAbstractCollector::CollectorRequestDefaultBehavior(t, requestID, param);
  246.         }
  247.     
  248.     return result;
  249.     } // TObjectCollector::CollectorRequestDefaultBehavior
  250.  
  251. //----------------------------------------------------------------------------------------
  252. // TObjectCollector::AddToCollection
  253. //----------------------------------------------------------------------------------------
  254. void TObjectCollector::AddToCollection(TAbstractScriptableObject* itemToAdd)
  255.     {
  256.     ++fNumberOfItemsAdded;
  257.     Boolean shouldAddToCollection =    (fNumberOfItemsAdded >= fStartOfRange) && ((fNumberOfItemsAdded <= fEndOfRange) || (fEndOfRange < 0));
  258.     
  259.     if((shouldAddToCollection == true) && (fCollectionFull == false))
  260.         {
  261.         if(fCollection == nil)
  262.             {
  263.             fCollection = new TMarkToken(kAlwaysMakeCollection);
  264.             fCollection->IMarkToken();
  265.             }
  266.             
  267.         //
  268.         // â—ŠScript:  Should the mark type be a field of TObjectCollector?
  269.         //
  270.         fCollection->AdoptToken(itemToAdd, kAlwaysMakeCollection);
  271.         if((fNumberOfItemsAdded >= fEndOfRange) && (fEndOfRange > 0))
  272.             fCollectionFull = true;
  273.         }
  274.     }
  275.     
  276. //----------------------------------------------------------------------------------------
  277. // TObjectCollector::CollectionResult
  278. //----------------------------------------------------------------------------------------
  279. TAbstractScriptableObject* TObjectCollector::CollectionResult()
  280.     {
  281.     //
  282.     // Before we return the collection, we must postprocess it to
  283.     // see if some items need to be pruned out (for example, if we're
  284.     // to return the middle item, then we want to prune out all but one
  285.     // item from the result list)
  286.     //
  287.     long firstItemToTake = fStartOfRange;
  288.     long lastItemToTake = fEndOfRange;
  289.     long middleItem = (fNumberOfItemsAdded + 1) >> 1;
  290.     
  291.     //
  292.     // Skip preprocessing if there were no items in the result
  293.     //
  294.     if(fNumberOfItemsAdded > 0)
  295.         {
  296.         switch(fPostProcessListStart)
  297.             {
  298.             case kAEMiddle:
  299.                 firstItemToTake = middleItem;
  300.                 break;
  301.             
  302.             case kAEAny:
  303.                 firstItemToTake = PseudoRandomFromMToN(1, fNumberOfItemsAdded);
  304.                 break;
  305.             
  306.             }
  307.             
  308.         switch(fPostProcessListStop)
  309.             {
  310.             case kAEMiddle:
  311.                 lastItemToTake = middleItem;
  312.                 break;
  313.                 
  314.             case kAEAny:
  315.                 lastItemToTake = PseudoRandomFromMToN(1, fNumberOfItemsAdded);
  316.                 break;
  317.                 
  318.             case kTakeFirstItemOnly:
  319.                 lastItemToTake = firstItemToTake;
  320.                 break;
  321.             }
  322.         
  323.         //
  324.         // If we already threw out some items, then adjust the
  325.         // range accordingly.
  326.         //
  327.         if(fStartOfRange > 1)
  328.             {
  329.             lastItemToTake -= (fStartOfRange - 1);
  330.             firstItemToTake -= (fStartOfRange - 1);
  331.             }
  332.         
  333.         //
  334.         // Just like the OSL, we call our adjust marks
  335.         // proc to prune down the list once we've determined
  336.         // which items to take.
  337.         //
  338.         if(fCollection)
  339.             fCollection->AdjustMarks(firstItemToTake, lastItemToTake);
  340.         }
  341.     
  342.     return fCollection;
  343.     }
  344.  
  345. //----------------------------------------------------------------------------------------
  346. // TObjectCollector::InterpretWhoseRangeEntry
  347. //
  348. // This routine does common pre-processing of a whose range entry; the
  349. // TObjectCollector uses the results from this routine to determine what
  350. // the appropriate range of items should actually be. 
  351. //----------------------------------------------------------------------------------------
  352. void TObjectCollector::InterpretWhoseRangeEntry(TDescriptor rangeEntry, long& start, long& end, unsigned long& special)
  353.     {
  354.     if(rangeEntry.DescriptorType() == typeLongInteger)
  355.         {
  356.         start = rangeEntry.GetSInt32Data();
  357.         end = start;
  358.         }
  359.     else if(rangeEntry.DescriptorType() == typeAbsoluteOrdinal)
  360.         {
  361.         DescType rangeEntryOrdinal = rangeEntry.GetDescTypeData(typeAbsoluteOrdinal);
  362.         switch(rangeEntryOrdinal)
  363.             {
  364.             case kAEFirst:
  365.                 start = 1;
  366.                 end = 1;
  367.                 break;
  368.             
  369.             case kAELast:
  370.                 start = -1;
  371.                 end = -1;
  372.                 break;
  373.             
  374.             case kAEMiddle:
  375.             case kAEAny:
  376.                 start = 1;
  377.                 end = 0x7FFFFFFF;
  378.                 special = rangeEntryOrdinal;
  379.                 break;
  380.             
  381.             case kAEAll:
  382.                 start = 1;
  383.                 end = 0x7FFFFFFF;
  384.                 break;
  385.             }
  386.         }
  387.     } // TObjectCollector::InterpretWhoseRangeEntry
  388.